package cloud.health.common.file.application.handler;

import cloud.health.common.file.application.FileService;
import cloud.health.common.file.domain.Request;
import cloud.health.common.file.infrastructure.R;
import cloud.health.common.file.infrastructure.RuntimeUtil;
import cn.hutool.http.HttpStatus;
import com.alibaba.fastjson.JSON;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 文件服务器管道处理
 */
@Slf4j
@Component
public class HttpChannelInboundHandler extends ChannelInboundHandlerAdapter {

    private static List<FileService> services;

    @Autowired
    public void init(final List<FileService> list) {
        HttpChannelInboundHandler.services = list;
    }

    private Request request;
    private FileService service;

    public void channelActive(ChannelHandlerContext ctx) {
        request = Request.init(ctx);
    }

    public void channelInactive(ChannelHandlerContext ctx) {
        request = null;
        service = null;
        ctx.close();
    }

    @SneakyThrows
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) {
        log.info("\nthread = {} channel = {} request = {}",
                Thread.currentThread().getId(),
                ctx.channel().id().asShortText(),
                request
        );
        long free = RuntimeUtil.freeMemory();
        ByteBuf buf = (ByteBuf) msg;
        try {
            if (Objects.isNull(request)) {
                request = Request.init(ctx);
            }
            request.accept(buf);

            if (Objects.nonNull(service)) {
                service.handle(request);
                if (request.completed()) {
                    log.info("{}", "执行结束");
                    request = null;
                    service = null;
                }
                return;
            }

            // 单列判断，创建并缓存实例
            Optional<FileService> opt = services.parallelStream().filter(it -> it.filter(request)).findFirst();
            if (opt.isPresent()) {
                service = opt.get().getClass().newInstance();
                service.handle(request);
                print(free);
                if (request.completed()) {
                    log.info("{}", "执行结束");
                    request = null;
                    service = null;
                }
                return;
            }
            // 找不到接口
            error(ctx);
        } finally {
            buf.release();
        }
    }

    private void print(long free) {
        RuntimeUtil.printGC();
        log.info("free = {}, MiB, cost = {}MiB",
                BigDecimal.valueOf(RuntimeUtil.freeMemory()).divide(BigDecimal.valueOf(1024 * 1024), 2, BigDecimal.ROUND_HALF_UP),
                BigDecimal.valueOf(RuntimeUtil.freeMemory() - free).divide(BigDecimal.valueOf(1024 * 1024), 2, BigDecimal.ROUND_HALF_UP));
    }

    private void error(ChannelHandlerContext ctx) {
        R r = R.fail(HttpStatus.HTTP_NOT_FOUND, "访问资源不存在或资源已删除");
        ctx.writeAndFlush(Unpooled.wrappedBuffer(r.response()));
        log.info("{}", "执行结束");
        request = null;
        service = null;
        ctx.close();
    }

}
